package com.appshelves.model;

import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;

import com.appshelves.PackageChangesReceiver;
import com.appshelves.utils.ComponentHelper;
import com.appshelves.utils.Profiler;
import com.appshelves.utils.Utils;
import com.appshelves.utils.Utils.ReadOperation;

class PackageChangesLoader {
    static enum Change {
        ADDED, REMOVED
    }

    class PackageChange {
        String packageName;
        Change change;
        long timeStamp;

        public PackageChange(String packageName, Change change, long timeStamp) {
            this.packageName = packageName;
            this.change = change;
            this.timeStamp = timeStamp;
        }

        public boolean isAdded() {
            return change == Change.ADDED;
        }

        public boolean checkSameName(PackageChange packageChange) {
            if (!packageName.equalsIgnoreCase(packageChange.packageName))
                return false;
            if (timeStamp < packageChange.timeStamp)
                replaceBy(packageChange);
            return true;
        }

        private void replaceBy(PackageChange packageChange) {
            onChangeReplaced(change, packageChange.change);
            timeStamp = packageChange.timeStamp;
            change = packageChange.change;
        }

    }

    List<PackageChange> packageChanges = new ArrayList<PackageChange>();
    EnumMap<Change, Integer> numChanges = new EnumMap<Change, Integer>(Change.class);

    public PackageChangesLoader() {
        for (Change change : Change.values())
            numChanges.put(change, 0);

        load();
    }

    void load() {
        Profiler p = new Profiler(this, "read changes");
        Utils.readFromFile(PackageChangesReceiver.CHANGES_FILE, new ReadOperation() {

            @Override
            public void run(DataInputStream stream) throws IOException {
                while (true) {
                    String readString = stream.readUTF();
                    String packageName = readString.substring(PackageChangesReceiver.PREFIX_LENGTH);
                    Change change = readString.startsWith(PackageChangesReceiver.ADDED_PACKAGE_PREFIX) ? Change.ADDED
                        : Change.REMOVED;

                    long timeStamp = stream.readLong();

                    addPackageChangeToList(new PackageChange(packageName, change, timeStamp));
                }

            }

            @Override
            public void onFail() {
            }
        });
        Utils.eraseDataFile(PackageChangesReceiver.CHANGES_FILE);
        p.e();
    }

    int getChangesNumber(Change change) {
        return numChanges.get(change);
    }

    List<PackageChange> getChangesList() {
        return packageChanges;
    }

    ///

    private void addPackageChangeToList(PackageChange packageChange) {
        if (ComponentHelper.isPackageSelf(packageChange.packageName))
            return;

        for (PackageChange pc : packageChanges)
            if (pc.checkSameName(packageChange))
                return;
        packageChanges.add(packageChange);
        increaseNumChanges(packageChange.change);
    }

    ///

    private void onChangeReplaced(Change oldChange, Change newChange) {
        if (oldChange == newChange)
            return;
        increaseNumChanges(newChange);
        decreaseNumChanges(oldChange);
    }

    private void decreaseNumChanges(Change change) {
        numChanges.put(change, numChanges.get(change) - 1);
    }

    private void increaseNumChanges(Change change) {
        numChanges.put(change, numChanges.get(change) + 1);
    }

}
